<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <style>
    .debounce_last {
      height: 200px;
      text-align: center;
      line-height: 200px;
      background-color: rgb(180, 252, 252);
    }

    .debounce_immediate {
      height: 200px;
      text-align: center;
      line-height: 200px;
      background-color: rgb(87, 87, 87);
    }

    .throttle_immediate {
      height: 200px;
      text-align: center;
      line-height: 200px;
      background-color: rgb(239, 197, 255);
    }

    .throttle_delay {
      height: 200px;
      text-align: center;
      line-height: 200px;
      background-color: rgb(186, 248, 200);
    }
  </style>
</head>

<body>

  <div class="debounce_last">debounce_last</div>
  <div class="debounce_immediate">debounce_immediate</div>
  <div class="throttle_immediate">throttle_immediate</div>
  <div class="throttle_delay">throttle_delay</div>

  <script>
    // 防抖 最后一次执行
    function debounce(foo, delay, ...args) {
      // 如果把timer写在内部，就需要使用闭包，不然事件回调函数每次触发完都会销毁数据，timer就不复存在，每次都是初始化的新timer
      // 写闭包，作用域链一直存在，这个函数内的scope的数据如timer不会被释放
      let timer

      // 每次看定时器

      return function () {
        const context = this;    //改变this指向
        clearTimeout(timer);   //先判断有没有延时器，有则清空，毕竟要最后一次执行
        timer = setTimeout(() => {
          foo.apply(context, args)     //apply调用传入方法
        }, delay);
      }

    }

    let debounce_last = document.querySelector('.debounce_last')
    let pageNum = 0


    // debounce_last.addEventListener('click', debounce(() => {
    //   fetch(`https://m.maizuo.com/gateway?cityId=310100&pageNum=${pageNum}&pageSize=5&type=1&k=7294968`, {
    //     headers: { 'X-Host': 'mall.film-ticket.film.list' }
    //   }).then(res => res.json()).then(res => {
    //     debounce_last.innerHTML = pageNum + ': ' + res.data.films.map(value => value.name + ' || ')
    //   })
    // }, 200))


    // 如果不写闭包，就要保证timer是全局的，因为每次click事件都会触发新的回调函数，每次执行完都会销毁内部空间，
    // 如果把timer写在函数内部，每次都初始化，但是闭包不会，return之后，作用域链一直存在，debounce_函数内的timer没有被释放
    // 见上面
    let timer
    function debounce_(foo, delay) {

      clearTimeout(timer)

      timer = setTimeout(() => {
        foo(timer)
      }, delay);
    }

    debounce_last.addEventListener('mouseup', (e) => {

      // 反映鼠标的左中右分别是0,1,2
      // console.log(e.button)

      // 根据鼠标的左中右键判断是否加还是减
      if (!e.button) pageNum++
      else pageNum--
      
      debounce_(() => {
        fetch(`https://m.maizuo.com/gateway?cityId=310100&pageNum=${pageNum}&pageSize=5&type=1&k=7294968`, {
          headers: { 'X-Host': 'mall.film-ticket.film.list' }
        }).then(res => res.json()).then(res => {
          debounce_last.innerHTML = pageNum + ': ' + res.data.films.map(value => value.name + ' || ')
        })
      }, 200)
    })



    // 立即执行的防抖
    function debounce_im(foo, delay, ...args) {
      let timer
      let call
      return function () {
        // 这个立即执行的防抖很巧妙
        // 每次timer都会被setTimeout返回赋值,每次timer有值就会清除定时器
        // 直到定时器成功后,才会把timer赋值为空, 这样, 下一次一开始call=timer就赋值为空了
        // 就能走一次if (!call) foo(...args),此后每次都会有timer被setTimeout赋值
        // 继续call又被timer赋值,直到定时器成功,timer又为null
        call = timer
        if (timer) {
          clearTimeout(timer)
        }
        timer = setTimeout(() => {
          timer = null
        }, delay);
        if (!call) foo(...args)
      }
    }

    let count = 0

    let debounce_immediate = document.querySelector('.debounce_immediate')
    debounce_immediate.onmousemove = debounce_im(() => {
      debounce_immediate.innerHTML = ++count
    }, 500)



    // 立即执行的节流

    function throttle_im(fun, delay, ...args) {
      let timer

      return function () {
        if (timer);
        else {
          // 不在定时器内，不会等待定时器完毕，即立即执行
          fun(...args)
          timer = setTimeout(() => {
            timer = null
          }, delay);
        }
      }

    }

    let throttle_immediate = document.querySelector('.throttle_immediate')
    throttle_immediate.addEventListener('mousemove', throttle_im(() => {
      throttle_immediate.innerHTML = ++count
    }, 1000))



    // 延后执行的节流

    function throttle_(fun, delay, ...args) {
      let timer

      return function () {
        if (timer);
        else {
          timer = setTimeout(() => {
            // 在定时器内，会等待定时器完毕，即延后执行
            fun(...args)
            timer = null
          }, delay);
        }
      }

    }

    let throttle_delay = document.querySelector('.throttle_delay')
    throttle_delay.addEventListener('mousemove', throttle_(() => {
      throttle_delay.innerHTML = ++count
    }, 1000))



  </script>
</body>

</html>